grammar AsmI8080;

options
{
	language = CSharp2;
	output=AST;
}

tokens
{
// no operands
OP_NOP  = 'nop' ;
OP_HLT  = 'hlt' ;
OP_EI   = 'ei' ;
OP_DI   = 'di' ;
OP_SPHL = 'sphl' ;
OP_XCHG = 'xchg' ;
OP_XTHL = 'xthl' ;
OP_DAA  = 'daa' ;
OP_CMA  = 'cma' ;
OP_STC  = 'stc' ;
OP_CMC  = 'cmc' ;
OP_RLC  = 'rlc' ;
OP_RRC  = 'rrc' ;
OP_RAL  = 'ral' ;
OP_RAR  = 'rar' ;
OP_PCHL = 'pchl' ;
OP_RET  = 'ret' ;
OP_RNZ  = 'rnz' ;
OP_RZ   = 'rz' ;
OP_RNC  = 'rnc' ;
OP_RC   = 'rc' ;
OP_RPO  = 'rpo' ;
OP_RPE  = 'rpe' ;
OP_RP   = 'rp' ;
OP_RM   = 'rm' ;
// im16
OP_LDA  = 'lda' ;
OP_STA  = 'sta' ;
OP_LHLD = 'lhld' ;
OP_SHLD = 'shld' ;
OP_JMP  = 'jmp' ;
OP_JNZ  = 'jnz' ;
OP_JZ   = 'jz' ;
OP_JNC  = 'jnc' ;
OP_JC   = 'jc' ;
OP_JPO  = 'jpo' ;
OP_JPE  = 'jpe' ;
OP_JP   = 'jp' ;
OP_JM   = 'jm' ;
OP_CALL = 'call' ;
OP_CNZ  = 'cnz' ;
OP_CZ   = 'cz' ;
OP_CNC  = 'cnc' ;
OP_CC   = 'cc' ;
OP_CPO  = 'cpo' ;
OP_CPE  = 'cpe' ;
OP_CP   = 'cp' ;
OP_CM   = 'cm' ;
// rp im16
OP_LXI  = 'lxi' ;
// im8
OP_ADI = 'adi' ;
OP_ACI = 'aci' ;
OP_SUI = 'sui' ;
OP_SBI = 'sbi' ;
OP_ANI = 'ani' ;
OP_XRI = 'xri' ;
OP_ORI = 'ori' ;
OP_CPI = 'cpi' ;
OP_IN  = 'in' ;
OP_OUT = 'out' ;
// reg im8
OP_MVI = 'mvi' ;
// reg reg
OP_MOV = 'mov' ;
// reg
OP_ADD = 'add' ;
OP_ADC = 'adc' ;
OP_SUB = 'sub' ;
OP_SBB = 'sbb' ;
OP_ANA = 'ana' ;
OP_XRA = 'xra' ;
OP_ORA = 'ora' ;
OP_CMP = 'cmp' ;
OP_INR = 'inr' ;
OP_DCR = 'dcr' ;
// rp
OP_LDAX = 'ldax' ;
OP_STAX = 'stax' ;
OP_DAD  = 'dad' ;
OP_INX  = 'inx' ;
OP_DCX  = 'dcx' ;
OP_PUSH = 'push' ;
OP_POP  = 'pop' ;
// included oparand
OP_RST  = 'rst'; // especial

// commands
CMD_ORG  = '.org';
CMD_DB   = '.db';
CMD_DW   = '.dw';
CMD_END  = '.end';

// token types
T_LABEL;
T_COMMENT;
T_OP_0;
T_OP_IM16;
T_OP_RP_IM16;
T_OP_IM8;
T_OP_REG_IM8;
T_OP_REG_REG;
T_OP_REG;
T_OP_RP;
T_OP_RST; // especial
T_REF_LABEL;
T_INT;
T_CMD;
}

@parser::namespace { Emu8080.Parser.GeneratedParser }
@lexer::namespace  { Emu8080.Parser.GeneratedLexer }

@parser::header
{
// disable warn with CLSComliant attribute
#pragma warning disable 3021
}

@lexer::header
{
// disable warn with CLSComliant attribute
#pragma warning disable 3021
}

public
parse
	:	asmBlocks
	;
	
asmBlocks
	:	asmAnonymousBlock? asmBlock+ asmEndStatement?
	;
	
asmAnonymousBlock
	:	asmStatement+
	;
	
asmBlock
	:	asmLabel+ asmStatement+
	;
	
asmEnd
	:	Newline!
	|	COMMENT -> ^(T_COMMENT COMMENT)
	;
	
asmStatement
	:	asmInstr asmEnd
	|	asmCommand asmEnd
	|	asmEnd
	;
	
asmCommand
	:	CMD_ORG integer 		-> ^(T_CMD ^(CMD_ORG integer))
	|	CMD_DB integer (',' integer)* 	-> ^(T_CMD ^(CMD_DB integer*))
	|	CMD_DW integer (',' integer)* 	-> ^(T_CMD ^(CMD_DW integer*))
	//|	CMD_END operand			-> ^(T_CMD ^(CMD_END  operand)) // end process in asmEndStatement
	;
	
asmEndStatement
	:	CMD_END operand? -> ^(T_CMD ^(CMD_END operand?))
	;
	
asmLabel
	:	ID COLON -> ^(T_LABEL ID)
	;
	
asmInstr
	:	
		(	op_0 					-> ^(T_OP_0 op_0)
		|	op_im16 operand 			-> ^(T_OP_IM16 ^(op_im16 operand))
		|	op_rp_im16 o1=operand ',' o2=operand 	-> ^(T_OP_RP_IM16 ^(op_rp_im16 $o1 $o2))
		|	op_im8 operand 				-> ^(T_OP_IM8 ^(op_im8 operand))
		|	op_reg_im8 o1=operand ',' o2=operand	-> ^(T_OP_REG_IM8 ^(op_reg_im8 $o1 $o2))
		|	op_reg_reg o1=operand ',' o2=operand	-> ^(T_OP_REG_REG ^(op_reg_reg $o1 $o2))
		|	op_reg operand				-> ^(T_OP_REG ^(op_reg operand))
		|	op_rp operand				-> ^(T_OP_RP ^(op_rp operand))
		|	op_rst operand				-> ^(T_OP_RST ^(op_rst operand))
		)
	;

op_0
	:	OP_NOP
	|	OP_HLT	
	|	OP_EI  
	|	OP_DI  
	|	OP_SPHL
	|	OP_XCHG
	|	OP_XTHL
	|	OP_DAA 
	|	OP_CMA 
	|	OP_STC 
	|	OP_CMC 
	|	OP_RLC 
	|	OP_RRC 
	|	OP_RAL 
	|	OP_RAR 
	|	OP_PCHL
	|	OP_RET 
	|	OP_RNZ 
	|	OP_RZ  
	|	OP_RNC 
	|	OP_RC  
	|	OP_RPO 
	|	OP_RPE 
	|	OP_RP  
	|	OP_RM
	
	;
	
op_im16
	:	OP_LDA 
	|	OP_STA 
	|	OP_LHLD
	|	OP_SHLD
	|	OP_JMP 
	|	OP_JNZ 
	|	OP_JZ  
	|	OP_JNC 
	|	OP_JC  
	|	OP_JPO 
	|	OP_JPE 
	|	OP_JP  
	|	OP_JM  
	|	OP_CALL
	|	OP_CNZ 
	|	OP_CZ  
	|	OP_CNC 
	|	OP_CC  
	|	OP_CPO 
	|	OP_CPE 
	|	OP_CP  
	|	OP_CM  
	;
	
op_rp_im16
	:	OP_LXI
	;
	
op_im8
	:	OP_ADI
	|	OP_ACI
	|	OP_SUI
	|	OP_SBI
	|	OP_ANI
	|	OP_XRI
	|	OP_ORI
	|	OP_CPI
	|	OP_IN 
	|	OP_OUT
	;
	
op_reg_im8
	:	OP_MVI
	;
	
op_reg_reg
	:	OP_MOV
	;
	
op_reg
	:	OP_ADD
	|	OP_ADC
	|	OP_SUB
	|	OP_SBB
	|	OP_ANA
	|	OP_XRA
	|	OP_ORA
	|	OP_CMP
	|	OP_INR
	|	OP_DCR
	;
	
op_rp
	:	OP_LDAX
	|	OP_STAX
	|	OP_DAD 
	|	OP_INX 
	|	OP_DCX 
	|	OP_PUSH
	|	OP_POP 
	;
	
op_rst
	:	OP_RST
	;

operand
	: HEX -> ^(T_INT HEX)
	| INT -> ^(T_INT INT)
	| ID -> ^(T_REF_LABEL ID)
	;
	
integer
	:	HEX
	|	INT
	;

/*
Label
	:	ID COLON
	;
	*/
Newline
	:	'\r'? '\n'
	;

INT
	:	('+'|'-')? ('0'..'9')+
	;
	
HEX
	:	('0'..'9') ('0'..'9'|'a'..'f'|'A'..'F')* 'h'
	;

ID  :	('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*
    ;

COMMENT
    :   ';' ~('\n'|'\r')* '\r'? '\n'
    ;

WS  :   ( ' '
        | '\t'
        | '\r'
        | '\n'
        ) {$channel=Hidden;}
    ;
    
COLON
	:	':'
	;
    
/*SEMI
	:	';'
	;
*/
	/*
ANY
	:	~('\n'|'\r')
	;*/
